/*********************************************************************************************************
* 模块名称：SPI.c
* 摘    要：SPI模块
* 当前版本：1.0.0
* 作    者：Leyutek(COPYRIGHT 2018 - 2021 Leyutek. All rights reserved.)
* 完成日期：2021年07月01日
* 内    容：
* 注    意：注意勾选Options for Target 'Target1'->Code Generation->Use MicroLIB，否则printf无法使用                                                                  
**********************************************************************************************************
* 取代版本：
* 作    者：
* 完成日期：
* 修改内容：
* 修改文件：
*********************************************************************************************************/

/*********************************************************************************************************
*                                              包含头文件
*********************************************************************************************************/
#include "SPI.h"
#include "gd32f470x_conf.h"
#include "stdio.h"

/*********************************************************************************************************
*                                              宏定义
*********************************************************************************************************/

/*********************************************************************************************************
*                                              内部变量
*********************************************************************************************************/

/*********************************************************************************************************
*                                              枚举结构体定义
*********************************************************************************************************/

/*********************************************************************************************************
*                                              内部函数声明
*********************************************************************************************************/

/*********************************************************************************************************
*                                              内部函数实现
*********************************************************************************************************/

/*********************************************************************************************************
*                                              API函数实现
*********************************************************************************************************/
/*********************************************************************************************************
* 函数名称：InitSPI4
* 函数功能：初始化SPI4
* 输入参数：void
* 输出参数：void
* 返 回 值：void
* 创建日期：2021年07月01日
* 注    意：
*********************************************************************************************************/
void InitSPI4(void)
{
  //SPI初始化结构体
  spi_parameter_struct spi_init_struct;

  rcu_periph_clock_enable(RCU_GPIOF); //使能GPIOF的时钟
  rcu_periph_clock_enable(RCU_SPI4);  //使能SPI4的时钟

  //禁止SPI4设备
  spi_disable(SPI4);

  //SPI4_CLK(PF7), SPI4_MISO(PF8), SPI4_MOSI(PF9)
  gpio_af_set(GPIOF, GPIO_AF_5, GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9);
  gpio_mode_set(GPIOF, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9);
  gpio_output_options_set(GPIOF, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9);

  //配置SPI4
  spi_struct_para_init(&spi_init_struct);
  spi_init_struct.device_mode          = SPI_MASTER;               //SPI主机
  spi_init_struct.trans_mode           = SPI_TRANSMODE_FULLDUPLEX; //全双工模式
  spi_init_struct.frame_size           = SPI_FRAMESIZE_8BIT;       //8位数据帧
  spi_init_struct.nss                  = SPI_NSS_SOFT;             //软件管理NSS（片选）
  spi_init_struct.endian               = SPI_ENDIAN_MSB;           //高位在前，低位在后数据位顺序
  spi_init_struct.clock_polarity_phase = SPI_CK_PL_HIGH_PH_2EDGE;  //时钟信号上升沿有效且第二个时钟跳变沿为有效采样边沿
  spi_init_struct.prescale             = SPI_PSC_4;                //时钟分频系数（由SYSCLK分频）
  spi_init(SPI4, &spi_init_struct);                                //根据参数配置SPI4

  //配置硬件CRC计算
  spi_crc_polynomial_set(SPI4, 7);

  //使能SPI4设备
  spi_enable(SPI4);
}

/*********************************************************************************************************
* 函数名称：SPI4SetSpeed
* 函数功能：设置SPI4传输速度
* 输入参数：void
* 输出参数：void
* 返 回 值：void
* 创建日期：2021年07月01日
* 注    意：
*********************************************************************************************************/
void SPI4SetSpeed(u32 pre)
{
  spi_disable(SPI4);
  SPI_CTL0(SPI4) &= ~(7 << 3);
  SPI_CTL0(SPI4)|= pre;
  spi_enable(SPI4);
}

/*********************************************************************************************************
* 函数名称：SPI4ReadWriteByte
* 函数功能：SPI4读写单字节
* 输入参数：void 
* 输出参数：void
* 返 回 值：void
* 创建日期：2021年07月01日
* 注    意：
*********************************************************************************************************/
unsigned char SPI4ReadWriteByte(unsigned char byte)
{
  //等待发送缓冲区空闲（等待上一批数据发送完成）
  while(RESET == spi_i2s_flag_get(SPI4, SPI_FLAG_TBE));

  //发送数据
  spi_i2s_data_transmit(SPI4, byte);

  //等待接收缓冲区非空（接收数据）
  while(RESET == spi_i2s_flag_get(SPI4, SPI_FLAG_RBNE));

  //获取SPI4数据输入
  return(spi_i2s_data_receive(SPI4));
}
